// 传入this对象，后面是调用函数时传入的参数args
function apply(fn, obj, args) {
    if (typeof fn !== 'function'){
        throw Error('fn must be a function')
    }
    if(args && !Array.isArray(args)){
        throw Error('args must be a array')
    }
    obj.fn = fn
    const res = obj.fn(...args)
    delete obj.fn
    return res
}
// args 是数组
function call(fn, obj, ...args){
    if(typeof fn !== 'function'){
        throw TypeError('fn must be a function')
    }
    return fn.apply(obj, args)
}

function bind(fn, obj, ...args) {
    if(typeof fn !== 'function'){
        throw TypeError('fn must be a function')
    }
    return function () {
        return fn.apply(obj, args)
    }
}
// 包装函数
function myNew(fn){
    if(typeof fn !== 'function'){
        throw TypeError('fn must be a function')
    }
    return function () {
        const obj = {"__proto__": fn.prototype}
        const res = fn.apply(obj, arguments)
        return res ? res : obj
    }
}
// 数组扁平化
function flat(arr){
    if (!Array.isArray(arr)){
        throw TypeError('arr must be an array')
    }
    const res = []
    for(let k in arr){
        let o = (arr[k] && typeof arr[k] === 'object') ? flat(arr[k]) : arr[k]
        res[k] = o
    }
    return res
}
// 函数柯里化
// 利用了闭包的知识，
function curry(fn){
    const len = fn.length
    const argus = []
    return function inner(...args) {
        let that = this
        if(arguments.length === 0){
            return fn.apply(that, argus)
        }
        argus = [...argus, ...args]
        return inner
    }
}
// 函数防抖节
// 隔了多少毫秒后
function debounce(fn, delay) {
    let timer = null
    return function(...args) {
        if(timer){
            clearTimeout(timer)
            timer = null
        }
        const that = this
        timer = setTimeout(()=>{
            fn.apply(that, args)
            timer = null
        }, delay)
    }
}
function throlle(fn, delay) {
    let timer = null
    let last = null;
    return function(...args) {
        if(timer){
             clearTimeout(timer)
             timer = null
        }
        let now = +new Date()
        const that = this
        if(last){
            let duration = last - now + delay
            if(t > 0) {
                timer = setTimeout(()=>{
                    fn.apply(that, args)
                    last = +new Date()
                }, duration)
            }
        }
        fn.apply(that, args)
        last = now;
    }
}

// Promise all race sleep [p1, p2, p3]链式调用

// 项目  --- 缓存  --- HTTP

// 发布订阅   观察者